import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;


/**
 * 计算通话时间与话费
 *
 * @author ZMC
 */
public class PhoneBill {

    /**
     * 计算通话时长(单位: 分钟)
     *
     * @param startTime 通话开始时间
     * @param endTime   通话结束时间
     * @return 通话时长(单位 : 分钟)
     */
    public static long calculateTimeSpan(LocalDateTime startTime, LocalDateTime endTime) {
        // 1.设置时区为美国纽约
        ZoneId zone = ZoneId.of("America/New_York");
        // 2.将开始时间和结束时间转化为指定时区的时间
        ZonedDateTime zonedStartTime = startTime.atZone(zone);
        ZonedDateTime zonedEndTime = endTime.atZone(zone);
        // 3.判断开始时间和结束时间是否在同一夏令时规则下
        boolean isSameRule = zonedStartTime.getOffset().equals(zonedEndTime.getOffset());
        // 4.不在同一夏令时规则下，需要调整结束时间
        if (!isSameRule) {
            // 4.1如果开始时间在夏令时期间，则结束时间需要增加1个小时
            if (zonedStartTime.getOffset()
                    .getTotalSeconds() > zonedEndTime.getOffset()
                    .getTotalSeconds()) {
                zonedEndTime = zonedEndTime.plusHours(1);
                // 4.2如果结束时间在夏令时期间，则开始时间需要增加1个小时
            } else {
                zonedStartTime = zonedStartTime.plusHours(1);
            }
        }
        // 5.计算通话时间
        java.time.Duration duration = java.time.Duration
                .between(zonedStartTime, zonedEndTime);
        // 6.将通话时间转化为分钟，并向上取整
        return (long) Math.ceil(duration.toMinutes());
    }

    /**
     * 计算通话费用(单位: 美元)
     *
     * @param callTime 通话时长(单位 : 分钟)
     * @return 通话费用(单位 : 美元)
     */
    public static BigDecimal calculateFee(long callTime) {
        // 1.通话时间超过30个小时，抛出非法数据异常
        if (callTime > 30 * 60) {
            throw new IllegalArgumentException("非法数据: 通话时间超过30分钟");
        }
        // 2.通话时间不足1分钟，按1分钟计算
        if (callTime < 1) {
            callTime = 1;
        }
        // 3.通话时间小于等于20分钟，每分钟收费0.05美元
        if (callTime <= 20) {
            return new BigDecimal(callTime).multiply(new BigDecimal("0.05"));
        }
        // 4.通话时间大于20分钟，收费1.00美元，外加超过20分钟的部分每分钟0.10美元
        return new BigDecimal("1.00").add(new BigDecimal(callTime - 20).multiply(new BigDecimal("0.10")));
    }

}
